home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / jove4.9 / part10 < prev    next >
Encoding:
Internet Message Format  |  1988-04-25  |  41.0 KB

  1. Subject:  v14i066:  Jove, an emacs variant, version 4.9, Part10/21
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
  7. Posting-number: Volume 14, Issue 66
  8. Archive-name: jove4.9/part10
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 10 (of 21)."
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f './extend.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'./extend.c'\"
  20. else
  21. echo shar: Extracting \"'./extend.c'\" \(19914 characters\)
  22. sed "s/^X//" >'./extend.c' <<'END_OF_FILE'
  23. X/***************************************************************************
  24. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  25. X * is provided to you without charge, and with no warranty.  You may give  *
  26. X * away copies of JOVE, including sources, provided that this notice is    *
  27. X * included in all the files.                                              *
  28. X ***************************************************************************/
  29. X
  30. X#include "jove.h"
  31. X#include "io.h"
  32. X#include "termcap.h"
  33. X#include "ctype.h"
  34. X#ifdef JOB_CONTROL
  35. X#    include <signal.h>
  36. X#endif
  37. X
  38. X#ifdef MAC
  39. X#    include "mac.h"
  40. X#else
  41. X#    include <varargs.h>
  42. X#endif
  43. X
  44. X#ifdef MSDOS
  45. X#include <process.h>
  46. X#endif
  47. X
  48. X#ifdef MAC
  49. X#    undef private
  50. X#    define private
  51. X#endif
  52. X
  53. X#ifdef    LINT_ARGS
  54. private    void
  55. X    fb_aux(data_obj *, data_obj **, char *, char *),
  56. X    find_binds(data_obj *, char *),
  57. X    vpr_aux(struct variable *, char *);
  58. X#else
  59. private    void
  60. X    fb_aux(),
  61. X    find_binds(),
  62. X    vpr_aux();
  63. X#endif    /* LINT_ARGS */
  64. X
  65. X#ifdef MAC
  66. X#    undef private
  67. X#    define private static
  68. X#endif
  69. X
  70. X
  71. int    InJoverc = 0;
  72. X
  73. extern int    getch(),
  74. X        getchar();
  75. X
  76. X/* Auto execute code */
  77. X
  78. X#define NEXECS    20
  79. X
  80. private struct {
  81. X    char    *a_pattern;
  82. X    data_obj    *a_cmd;
  83. X} AutoExecs[NEXECS] = {0};
  84. X
  85. private int    ExecIndex = 0;
  86. X
  87. X/* Command auto-execute. */
  88. X
  89. void
  90. CAutoExec()
  91. X{
  92. X    DefAutoExec(findcom);
  93. X}
  94. X
  95. X/* Macro auto-execute. */
  96. X
  97. void
  98. MAutoExec()
  99. X{
  100. X    DefAutoExec(findmac);
  101. X}
  102. X
  103. X/* VARARGS0 */
  104. X
  105. void
  106. DefAutoExec(proc)
  107. X#ifdef LINT_ARGS
  108. data_obj    *(*proc)();
  109. X#else
  110. data_obj    *(*proc)();
  111. X#endif
  112. X{
  113. X    data_obj    *d;
  114. X    char    *pattern;
  115. X    int    i;
  116. X
  117. X    if (ExecIndex >= NEXECS)
  118. X        complain("Too many auto-executes, max %d.", NEXECS);
  119. X    if ((d = (*proc)(ProcFmt)) == 0)
  120. X        return;
  121. X    pattern = do_ask("\r\n", (int (*)()) 0, (char *) 0, ": %f %s ", d->Name);
  122. X    if (pattern != 0)
  123. X        for (i = 0; i < ExecIndex; i++)
  124. X        if ((AutoExecs[i].a_cmd == d) &&
  125. X            (strcmp(pattern, AutoExecs[i].a_pattern) == 0))
  126. X                return;        /* eliminate duplicates */
  127. X    AutoExecs[ExecIndex].a_pattern = copystr(pattern);
  128. X    AutoExecs[ExecIndex].a_cmd = d;
  129. X    ExecIndex += 1;
  130. X}
  131. X
  132. X/* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
  133. X   same kind of file (i.e., match the same pattern) or OLD is 0 and it
  134. X   matches, OR if the pattern is 0 (none was specified) then, we execute
  135. X   the command associated with that kind of file. */
  136. X
  137. void
  138. DoAutoExec(new, old)
  139. register char    *new,
  140. X        *old;
  141. X{
  142. X    register int    i;
  143. X
  144. X    set_arg_value(1);
  145. X    for (i = 0; i < ExecIndex; i++)
  146. X        if ((AutoExecs[i].a_pattern == 0) ||
  147. X            ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
  148. X             (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
  149. X            ExecCmd(AutoExecs[i].a_cmd);
  150. X}
  151. X
  152. void
  153. BindAKey()
  154. X{
  155. X    BindSomething(findcom);
  156. X}
  157. X
  158. void
  159. BindMac()
  160. X{
  161. X    BindSomething(findmac);
  162. X}
  163. X
  164. extern void    EscPrefix(),
  165. X        CtlxPrefix(),
  166. X        MiscPrefix();
  167. X
  168. data_obj **
  169. IsPrefix(cp)
  170. data_obj    *cp;
  171. X{
  172. X#ifdef MAC
  173. X    void (*proc)();
  174. X#else
  175. X    int    (*proc)();
  176. X#endif
  177. X    
  178. X    if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION)
  179. X        return 0;
  180. X    proc = ((struct cmd *) cp)->c_proc;
  181. X    if (proc == EscPrefix)
  182. X        return pref1map;
  183. X    if (proc == CtlxPrefix)
  184. X        return pref2map;
  185. X    if (proc == MiscPrefix)
  186. X        return miscmap;
  187. X    return 0;
  188. X}
  189. X
  190. void
  191. UnbindC()
  192. X{
  193. X    char    *keys;
  194. X    data_obj    **map = mainmap;
  195. X
  196. X    keys = ask((char *) 0, ProcFmt);
  197. X    for (;;) {
  198. X        if (keys[1] == '\0')
  199. X            break;
  200. X        if ((map = IsPrefix(map[*keys])) == 0)
  201. X            break;
  202. X        keys += 1;
  203. X    }
  204. X    if (keys[1] != 0)
  205. X        complain("That's not a legitimate key sequence.");
  206. X    map[keys[0]] = 0;
  207. X}
  208. X        
  209. int
  210. addgetc()
  211. X{
  212. X    int    c;
  213. X
  214. X    if (!InJoverc) {
  215. X        Asking = strlen(mesgbuf);
  216. X        c = getch();
  217. X        Asking = 0;
  218. X        add_mess("%p ", c);
  219. X    } else {
  220. X        c = getch();
  221. X        if (c == '\n')
  222. X            return EOF;    /* this isn't part of the sequence */
  223. X        else if (c == '\\') {
  224. X            if ((c = getch()) == LF)
  225. X                complain("[Premature end of line]");
  226. X        } else if (c == '^') {
  227. X            if ((c = getch()) == '?')
  228. X                c = RUBOUT;
  229. X            else if (isalpha(c) || index("@[\\]^_", c))
  230. X                c = CTL(c);
  231. X            else
  232. X                complain("[Unknown control character]");
  233. X        }
  234. X    }
  235. X    return c;
  236. X}
  237. X
  238. void
  239. BindWMap(map, lastkey, cmd)
  240. data_obj    **map,
  241. X        *cmd;
  242. X{
  243. X    data_obj    **nextmap;
  244. X    int    c;
  245. X
  246. X    c = addgetc();
  247. X    if (c == EOF) {
  248. X        if (lastkey == EOF)
  249. X            complain("[Empty key sequence]");
  250. X        complain("[Premature end of key sequence]");
  251. X    } else {
  252. X        if (nextmap = IsPrefix(map[c]))
  253. X            BindWMap(nextmap, c, cmd);
  254. X        else {
  255. X            map[c] = cmd;
  256. X#ifdef MAC
  257. X            ((struct cmd *) cmd)->c_key = c;    /* see about_j() in mac.c */
  258. X            if(map == mainmap) ((struct cmd *) cmd)->c_map = F_MAINMAP;
  259. X            else if(map == pref1map) ((struct cmd *) cmd)->c_map = F_PREF1MAP;
  260. X            else if(map == pref2map) ((struct cmd *) cmd)->c_map = F_PREF2MAP;
  261. X#endif
  262. X        }
  263. X    }
  264. X}
  265. X
  266. X/* VARARGS0 */
  267. X
  268. void
  269. BindSomething(proc)
  270. X#ifdef LINT_ARGS
  271. data_obj    *(*proc)();
  272. X#else
  273. data_obj    *(*proc)();
  274. X#endif
  275. X{
  276. X    data_obj    *d;
  277. X
  278. X    if ((d = (*proc)(ProcFmt)) == 0)
  279. X        return;
  280. X    s_mess(": %f %s ", d->Name);
  281. X    BindWMap(mainmap, EOF, d);
  282. X}
  283. X
  284. X/* Describe key */
  285. X
  286. void
  287. DescWMap(map, key)
  288. data_obj    **map;
  289. X{
  290. X    data_obj    *cp = map[key],
  291. X            **prefp;
  292. X
  293. X    if (cp == 0)
  294. X        add_mess("is unbound.");
  295. X    else if (prefp = IsPrefix(cp))
  296. X        DescWMap(prefp, addgetc());
  297. X    else
  298. X        add_mess("is bound to %s.", cp->Name);
  299. X}
  300. X
  301. void
  302. KeyDesc()
  303. X{
  304. X    s_mess(ProcFmt);
  305. X    DescWMap(mainmap, addgetc());
  306. X}
  307. X
  308. void
  309. DescCom()
  310. X{
  311. X    data_obj    *dp;
  312. X    char    pattern[100],
  313. X        doc_type[40],
  314. X        *file = CmdDb;
  315. X    File    *fp;
  316. X
  317. X    if (!strcmp(LastCmd->Name, "describe-variable"))
  318. X        dp = (data_obj *) findvar(ProcFmt);
  319. X    else
  320. X        dp = (data_obj *) findcom(ProcFmt);
  321. X    if (dp == 0)
  322. X        return;
  323. X    fp = open_file(file, iobuff, F_READ, COMPLAIN, QUIET);
  324. X    Placur(ILI, 0);
  325. X    flusho();
  326. X    sprintf(pattern, "^:entry \"%s\" \"\\([^\"]*\\)\"", dp->Name);
  327. X    TOstart("Help", TRUE);
  328. X    for (;;) {
  329. X        if (f_gets(fp, genbuf, LBSIZE) == EOF) {
  330. X            Typeout("There is no documentation for \"%s\".", dp->Name);
  331. X            goto outahere;
  332. X        }
  333. X        if ((strncmp(genbuf, ":entry", 6) == 0) && LookingAt(pattern, genbuf, 0))
  334. X            break;
  335. X    }
  336. X    /* found it ... let's print it */
  337. X    putmatch(1, doc_type, sizeof doc_type);
  338. X    if (strcmp("Variable", doc_type) == 0)
  339. X        Typeout(dp->Name);
  340. X    else if (strcmp("Command", doc_type) == 0) {
  341. X        char    binding[128];
  342. X
  343. X        find_binds(dp, binding);
  344. X        if (blnkp(binding))
  345. X            Typeout("To invoke %s, type \"ESC X %s<cr>\".",
  346. X                dp->Name,
  347. X                dp->Name);
  348. X        else
  349. X            Typeout("Type \"%s\" to invoke %s.", binding, dp->Name);
  350. X    }
  351. X    Typeout("");
  352. X    while (f_gets(fp, genbuf, LBSIZE) != EOF)
  353. X        if (strncmp(genbuf, ":entry", 6) == 0)
  354. X            goto outahere;
  355. X        else
  356. X            Typeout("%s", genbuf);
  357. outahere:
  358. X    f_close(fp);
  359. X    TOstop();
  360. X}
  361. X
  362. void
  363. DescBindings()
  364. X{
  365. X    extern void    Typeout();
  366. X
  367. X    TOstart("Key Bindings", TRUE);
  368. X    DescMap(mainmap, NullStr);
  369. X    TOstop();
  370. X}
  371. X
  372. extern int specialmap;
  373. X
  374. void
  375. DescMap(map, pref)
  376. data_obj    **map;
  377. char    *pref;
  378. X{
  379. X    int    c1,
  380. X        c2 = 0,
  381. X        numbetween;
  382. X    char    keydescbuf[40];
  383. X    data_obj    **prefp;
  384. X
  385. X#ifdef IBMPC
  386. X    specialmap = (map == miscmap);
  387. X#endif
  388. X
  389. X    for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
  390. X        c2 = c1;
  391. X        if (map[c1] == 0)
  392. X            continue;
  393. X        while (++c2 < NCHARS && map[c1] == map[c2])
  394. X            ;
  395. X        c2 -= 1;
  396. X        numbetween = c2 - c1;
  397. X        if (numbetween == 1)
  398. X            sprintf(keydescbuf, "%s {%p,%p}", pref, c1, c2);
  399. X        else if (numbetween == 0)
  400. X            sprintf(keydescbuf, "%s %p", pref, c1);
  401. X        else
  402. X            sprintf(keydescbuf, "%s [%p-%p]", pref, c1, c2);
  403. X        if ((prefp = IsPrefix(map[c1])) && (prefp != map))
  404. X            DescMap(prefp, keydescbuf);
  405. X        else
  406. X            Typeout("%-18s%s", keydescbuf, map[c1]->Name);
  407. X    }
  408. X}
  409. X
  410. private void
  411. find_binds(dp, buf)
  412. data_obj    *dp;
  413. char    *buf;
  414. X{
  415. X    char    *endp;
  416. X
  417. X    buf[0] = '\0';
  418. X    fb_aux(dp, mainmap, (char *) 0, buf);
  419. X    endp = buf + strlen(buf) - 2;
  420. X    if ((endp > buf) && (strcmp(endp, ", ") == 0))
  421. X        *endp = '\0';
  422. X}
  423. X
  424. private void
  425. fb_aux(cp, map, prefix, buf)
  426. register data_obj    *cp,
  427. X            **map;
  428. char    *buf,
  429. X    *prefix;
  430. X{
  431. X    int    c1,
  432. X        c2;
  433. X    char    *bufp = buf + strlen(buf),
  434. X        prefbuf[20];
  435. X    data_obj    **prefp;
  436. X
  437. X#ifdef IBMPC
  438. X    specialmap = (map == miscmap);
  439. X#endif    
  440. X
  441. X    for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
  442. X        c2 = c1;
  443. X        if (map[c1] == cp) {
  444. X            while (++c2 < NCHARS && map[c1] == map[c2])
  445. X                ;
  446. X            c2 -= 1;
  447. X            if (prefix)
  448. X                sprintf(bufp, "%s ", prefix);
  449. X            bufp += strlen(bufp);
  450. X            switch (c2 - c1) {
  451. X            case 0:
  452. X                sprintf(bufp, "%p, ", c1);
  453. X                break;
  454. X    
  455. X            case 1:
  456. X                sprintf(bufp, "{%p,%p}, ", c1, c2);
  457. X                break;
  458. X    
  459. X            default:
  460. X                sprintf(bufp, "[%p-%p], ", c1, c2);
  461. X                break;
  462. X            }
  463. X        }
  464. X        if ((prefp = IsPrefix(map[c1])) && (prefp != map))  {
  465. X            sprintf(prefbuf, "%p", c1);
  466. X            fb_aux(cp, prefp, prefbuf, bufp);
  467. X        }
  468. X        bufp += strlen(bufp);
  469. X    }
  470. X}
  471. X
  472. void
  473. Apropos()
  474. X{
  475. X    register struct cmd    *cp;
  476. X    register struct macro    *m;
  477. X    register struct variable    *v;
  478. X    char    *ans;
  479. X    int    anyfs = NO,
  480. X        anyvs = NO,
  481. X        anyms = NO;
  482. X    char    buf[256];
  483. X
  484. X    ans = ask((char *) 0, ": %f (keyword) ");
  485. X    TOstart("Help", TRUE);
  486. X    for (cp = commands; cp->Name != 0; cp++)
  487. X        if (sindex(ans, cp->Name)) {
  488. X            if (anyfs == 0) {
  489. X                Typeout("Commands");
  490. X                Typeout("--------");
  491. X            }
  492. X            find_binds((data_obj *) cp, buf);
  493. X            if (buf[0])
  494. X                Typeout(": %-35s(%s)", cp->Name, buf);
  495. X            else
  496. X                Typeout(": %s", cp->Name);
  497. X            anyfs = YES;
  498. X        }
  499. X    if (anyfs)
  500. X        Typeout(NullStr);
  501. X    for (v = variables; v->Name != 0; v++)
  502. X        if (sindex(ans, v->Name)) {
  503. X            if (anyvs == 0) {
  504. X                Typeout("Variables");
  505. X                Typeout("---------");
  506. X            }
  507. X            anyvs = YES;
  508. X            vpr_aux(v, buf);
  509. X            Typeout(": set %-26s%s", v->Name, buf);
  510. X        }
  511. X    if (anyvs)
  512. X        Typeout(NullStr);
  513. X    for (m = macros; m != 0; m = m->m_nextm)
  514. X        if (sindex(ans, m->Name)) {
  515. X            if (anyms == 0) {
  516. X                Typeout("Macros");
  517. X                Typeout("------");
  518. X            }
  519. X            anyms = YES;
  520. X            find_binds((data_obj *) m, buf);
  521. X            if (buf[0])
  522. X                Typeout(": %-35s(%s)", m->Name, buf);
  523. X            else
  524. X                Typeout(": %-35s%s", "execute-macro", m->Name);
  525. X        }
  526. X    TOstop();
  527. X}
  528. X
  529. void
  530. Extend()
  531. X{
  532. X    data_obj    *d;
  533. X
  534. X    if (d = findcom(": "))
  535. X        ExecCmd(d);
  536. X}
  537. X
  538. X/* Read a positive integer from CP.  It must be in base BASE, and
  539. X   complains if it isn't.  If allints is nonzero, all the characters
  540. X   in the string must be integers or we return -1; otherwise we stop
  541. X   reading at the first nondigit. */
  542. X
  543. int
  544. chr_to_int(cp, base, allints, result)
  545. register char    *cp;
  546. register int    *result;
  547. X{
  548. X    register int    c;
  549. X    int    value = 0,
  550. X        sign;
  551. X
  552. X    if ((c = *cp) == '-') {
  553. X        sign = -1;
  554. X        cp += 1;
  555. X    } else
  556. X        sign = 1;
  557. X    while (c = *cp++) {
  558. X        if (!isdigit(c)) {
  559. X            if (allints == YES)
  560. X                return INT_BAD;
  561. X            break;
  562. X        }
  563. X        c = c - '0';
  564. X        if (c >= base)
  565. X            complain("You must specify in base %d.", base);
  566. X        value = value * base + c;
  567. X    }
  568. X    *result = value * sign;
  569. X    return INT_OKAY;
  570. X}
  571. X
  572. int
  573. ask_int(prompt, base)
  574. char    *prompt;
  575. int    base;
  576. X{
  577. X    char    *val = ask((char *) 0, prompt);
  578. X    int    value;
  579. X
  580. X    if (chr_to_int(val, base, YES, &value) == INT_BAD)
  581. X        complain("That's not a number!");
  582. X    return value;
  583. X}
  584. X
  585. private void
  586. vpr_aux(vp, buf)
  587. register struct variable    *vp;
  588. char    *buf;
  589. X{
  590. X    switch (vp->v_flags & V_TYPEMASK) {
  591. X    case V_BASE10:
  592. X        sprintf(buf, "%d", *(vp->v_value));
  593. X        break;
  594. X
  595. X    case V_BASE8:
  596. X        sprintf(buf, "%o", *(vp->v_value));
  597. X        break;
  598. X
  599. X    case V_BOOL:
  600. X        sprintf(buf, (*(vp->v_value)) ? "on" : "off");
  601. X        break;
  602. X
  603. X    case V_STRING:
  604. X    case V_FILENAME:
  605. X        sprintf(buf, "%s", (char *) vp->v_value);
  606. X        break;
  607. X
  608. X    case V_CHAR:
  609. X        sprintf(buf, "%p", *(vp->v_value));
  610. X        break;
  611. X    }
  612. X}
  613. X
  614. void
  615. PrVar()
  616. X{
  617. X    struct variable    *vp;
  618. X    char    prbuf[256];
  619. X
  620. X    if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
  621. X        return;
  622. X    vpr_aux(vp, prbuf);
  623. X    s_mess(": %f %s => %s", vp->Name, prbuf);
  624. X}
  625. X
  626. void
  627. SetVar()
  628. X{
  629. X    struct variable    *vp;
  630. X    char    *prompt;
  631. X
  632. X    if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
  633. X        return;
  634. X    prompt = sprint(": %f %s ", vp->Name);
  635. X
  636. X    switch (vp->v_flags & V_TYPEMASK) {
  637. X    case V_BASE10:
  638. X    case V_BASE8:
  639. X        {
  640. X            int    value;
  641. X
  642. X        value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
  643. X                      ? 10 : 8);
  644. X        *(vp->v_value) = value;
  645. X            break;
  646. X        }
  647. X
  648. X    case V_BOOL:
  649. X        {
  650. X            char    *def = *(vp->v_value) ? "off" : "on",
  651. X                *on_off;
  652. X            int    value;
  653. X
  654. X            on_off = ask(def, prompt);
  655. X        if (casecmp(on_off, "on") == 0)
  656. X            value = ON;
  657. X            else if (casecmp(on_off, "off") == 0)
  658. X                value = OFF;
  659. X            else
  660. X                complain("Boolean variables must be ON or OFF.");
  661. X            *(vp->v_value) = value;
  662. X#ifdef MAC
  663. X        MarkVar(vp,-1,0);    /* mark the menu item */
  664. X#endif
  665. X            s_mess("%s%s", prompt, value ? "on" : "off");
  666. X            break;
  667. X        }
  668. X
  669. X    case V_FILENAME:
  670. X        {
  671. X        char    fbuf[FILESIZE];
  672. X
  673. X            sprintf(&prompt[strlen(prompt)], "(default %s) ", vp->v_value);
  674. X            (void) ask_file(prompt, (char *) vp->v_value, fbuf);
  675. X        strcpy((char *) vp->v_value, fbuf);
  676. X            break;
  677. X        }
  678. X
  679. X    case V_STRING:
  680. X        {
  681. X        char    *str;
  682. X
  683. X            /* Do_ask() so you can set string to "" if you so desire. */
  684. X            str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt);
  685. X            if (str == 0)
  686. X            str = NullStr;
  687. X            strcpy((char *) vp->v_value, str);
  688. X        /* ... and hope there is enough room. */
  689. X            break;
  690. X        }
  691. X    case V_CHAR:
  692. X        f_mess(prompt);
  693. X            *(vp->v_value) = addgetc();
  694. X        break;            
  695. X
  696. X    }
  697. X    if (vp->v_flags & V_MODELINE)
  698. X        UpdModLine = YES;
  699. X    if (vp->v_flags & V_CLRSCREEN) {
  700. X#ifdef IBMPC
  701. X        setcolor(Fgcolor, Bgcolor);
  702. X#endif /* IBMPC */
  703. X        ClAndRedraw();
  704. X    }
  705. X    if (vp->v_flags & V_TTY_RESET)
  706. X        tty_reset();
  707. X}
  708. X            
  709. X/* Command completion - possible is an array of strings, prompt is
  710. X   the prompt to use, and flags are ... well read jove.h.
  711. X
  712. X   If flags are RET_STATE, and the user hits <return> what they typed
  713. X   so far is in the Minibuf string. */
  714. X
  715. private char    **Possible;
  716. private int    comp_value,
  717. X        comp_flags;
  718. X
  719. int
  720. aux_complete(c)
  721. X{
  722. X    int    command,
  723. X        length,
  724. X        i;
  725. X
  726. X    if (comp_flags & CASEIND) {
  727. X        char    *lp;
  728. X
  729. X        for (lp = linebuf; *lp != '\0'; lp++)
  730. X#if (defined(IBMPC) || defined(MAC))
  731. X            lower(lp);
  732. X#else            
  733. X            if (isupper(*lp))
  734. X                *lp = tolower(*lp);
  735. X#endif
  736. X    }
  737. X    switch (c) {
  738. X    case EOF:
  739. X        comp_value = -1;
  740. X        return 0;
  741. X
  742. X    case '\r':
  743. X    case '\n':
  744. X        command = match(Possible, linebuf);
  745. X        if (command >= 0) {
  746. X            comp_value = command;
  747. X            return 0;    /* tells ask to stop */
  748. X        }
  749. X        if (eolp() && bolp()) {
  750. X            comp_value = NULLSTRING;
  751. X            return 0;
  752. X        }
  753. X        if (comp_flags & RET_STATE) {
  754. X            comp_value = command;
  755. X            return 0;
  756. X        }
  757. X        if (InJoverc)
  758. X            complain("[\"%s\" unknown]", linebuf);
  759. X        rbell();
  760. X        break;
  761. X
  762. X    case '\t':
  763. X    case ' ':
  764. X        {
  765. X        int    minmatch = 1000,
  766. X                maxmatch = 0,
  767. X                numfound = 0,
  768. X                lastmatch = -1,
  769. X            length = strlen(linebuf);
  770. X
  771. X        for (i = 0; Possible[i] != 0; i++) {
  772. X            int    this_len;
  773. X
  774. X            this_len = numcomp(Possible[i], linebuf);
  775. X            maxmatch = max(maxmatch, this_len);
  776. X            if (this_len >= length) {
  777. X                if (numfound)
  778. X                    minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
  779. X                else
  780. X                    minmatch = strlen(Possible[i]);
  781. X                numfound += 1;
  782. X                lastmatch = i;
  783. X                if (strcmp(linebuf, Possible[i]) == 0)
  784. X                    break;
  785. X            }
  786. X        }
  787. X
  788. X        if (numfound == 0) {
  789. X            rbell();
  790. X            if (InJoverc)
  791. X                complain("[\"%s\" unknown]", linebuf);
  792. X            /* If we're not in the .joverc then
  793. X               let's do something helpful for the
  794. X               user. */
  795. X            if (maxmatch < length) {
  796. X                char    *cp;
  797. X
  798. X                cp = linebuf + maxmatch;
  799. X                *cp = 0;
  800. X                Eol();
  801. X            }
  802. X            break;
  803. X        }
  804. X            if (c != '\t' && numfound == 1) {
  805. X                comp_value = lastmatch;
  806. X            return 0;
  807. X        }
  808. X        null_ncpy(linebuf, Possible[lastmatch], minmatch);
  809. X            Eol();
  810. X        if (minmatch == length)    /* No difference */
  811. X            rbell();
  812. X        break;
  813. X        }
  814. X
  815. X    case '?':
  816. X        if (InJoverc)
  817. X            complain((char *) 0);
  818. X        /* kludge: in case we're using UseBuffers, in which case
  819. X           linebuf gets written all over */
  820. X        strcpy(Minibuf, linebuf);
  821. X        length = strlen(Minibuf);
  822. X        TOstart("Completion", TRUE);    /* for now ... */
  823. X        for (i = 0; Possible[i]; i++)
  824. X            if (numcomp(Possible[i], Minibuf) >= length) {
  825. X                Typeout(Possible[i]);
  826. X                if (TOabort != 0)
  827. X                    break;
  828. X            }
  829. X
  830. X        TOstop();
  831. X        break;
  832. X    }
  833. X    return !FALSE;
  834. X}
  835. X
  836. int
  837. complete(possible, prompt, flags)
  838. register char    *possible[];
  839. char    *prompt;
  840. X{
  841. X    Possible = possible;
  842. X    comp_flags = flags;
  843. X    (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
  844. X    return comp_value;
  845. X}
  846. X
  847. int
  848. match(choices, what)
  849. register char    **choices,
  850. X        *what;
  851. X{
  852. X    register int    len;
  853. X    int    i,
  854. X        found = 0,
  855. X        save,
  856. X        exactmatch = -1;
  857. X
  858. X    len = strlen(what);
  859. X    if (len == 0)
  860. X        return NULLSTRING;
  861. X    for (i = 0; choices[i]; i++) {
  862. X        if (strncmp(what, choices[i], len) == 0) {
  863. X            if (strcmp(what, choices[i]) == 0)
  864. X                exactmatch = i;
  865. X            save = i;
  866. X            found += 1;    /* found one */
  867. X        }
  868. X    }
  869. X
  870. X    if (found == 0)
  871. X        save = ORIGINAL;
  872. X    else if (found > 1) {
  873. X        if (exactmatch != -1)
  874. X            save = exactmatch;
  875. X        else
  876. X            save = AMBIGUOUS;
  877. X    }
  878. X
  879. X    return save;
  880. X}
  881. X
  882. void
  883. Source()
  884. X{
  885. X    char    *com, *getenv(),
  886. X        buf[FILESIZE];
  887. X
  888. X#ifndef MSDOS
  889. X    sprintf(buf, "%s/.joverc", getenv("HOME"));
  890. X#else /* MSDOS */
  891. X    if (com = getenv("JOVERC"))
  892. X        strcpy(buf, com);
  893. X    else
  894. X        strcpy(buf, Joverc);
  895. X#endif /* MSDOS */
  896. X    com = ask_file((char *) 0, buf, buf);
  897. X    if (joverc(buf) == 0)
  898. X        complain(IOerr("read", com));
  899. X}
  900. X
  901. void
  902. BufPos()
  903. X{
  904. X    register Line    *lp = curbuf->b_first;
  905. X    register int    i,
  906. X            dotline;
  907. X    long    dotchar,
  908. X        nchars;
  909. X
  910. X    for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
  911. X        if (lp == curline) {
  912. X            dotchar = nchars + curchar;
  913. X            dotline = i + 1;
  914. X        }
  915. X        nchars += length(lp) + (lp->l_next != 0); /* include the NL */
  916. X    }
  917. X
  918. X    s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
  919. X           filename(curbuf), dotline, i, dotchar, nchars,
  920. X           (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
  921. X           calc_pos(linebuf, curchar),
  922. X           calc_pos(linebuf, strlen(linebuf)));
  923. X}
  924. X
  925. X#define IF_UNBOUND    -1
  926. X#define IF_TRUE        1
  927. X#define IF_FALSE    !IF_TRUE
  928. X
  929. X#ifndef MAC
  930. int
  931. do_if(cmd)
  932. char    *cmd;
  933. X{
  934. X#ifdef MSDOS
  935. X    int status;
  936. X#else    
  937. X    int    pid,
  938. X        status;
  939. X#endif /* MSDOS */
  940. X#ifndef MSDOS
  941. X
  942. X    switch (pid = fork()) {
  943. X    case -1:
  944. X        complain("[Fork failed: if]");
  945. X
  946. X    case 0:
  947. X        {
  948. X#endif /* MSDOS */
  949. X        char    *args[12],
  950. X            *cp = cmd,
  951. X            **ap = args;
  952. X
  953. X            *ap++ = cmd;
  954. X            for (;;) {
  955. X            if ((cp = index(cp, ' ')) == 0)
  956. X                break;
  957. X            *cp++ = '\0';
  958. X            *ap++ = cp;
  959. X        }
  960. X        *ap = 0;
  961. X
  962. X#ifndef MSDOS
  963. X        close(0);    /*    we want reads to fail */
  964. X        /* close(1);     but not writes or ioctl's
  965. X        close(2);    */
  966. X#else /* MSDOS */
  967. X    if ((status = spawnvp(0, args[0], args)) < 0)
  968. X        complain("[Spawn failed: if]");
  969. X#endif /* MSDOS */
  970. X
  971. X#ifndef MSDOS
  972. X            (void) execvp(args[0], args);
  973. X        _exit(-10);    /* signals exec error (see below) */
  974. X        }
  975. X    }
  976. X#ifdef IPROCS
  977. X    sighold(SIGCHLD);
  978. X#endif
  979. X    dowait(pid, &status);
  980. X#ifdef IPROCS
  981. X    sigrelse(SIGCHLD);
  982. X#endif
  983. X    if (status == -10)
  984. X        complain("[Exec failed]");
  985. X    if (status < 0)
  986. X        complain("[Exit %d]", status);
  987. X#endif /* MSDOS */
  988. X    return (status == 0);    /* 0 means successful */
  989. X}
  990. X#endif /* MAC */
  991. X
  992. int
  993. joverc(file)
  994. char    *file;
  995. X{
  996. X    char    buf[LBSIZE],
  997. X        lbuf[LBSIZE];
  998. X    int    lnum = 0,
  999. X        eof = FALSE;
  1000. X    jmp_buf    savejmp;
  1001. X    int    IfStatus = IF_UNBOUND;
  1002. X    File    *fp;
  1003. X
  1004. X    fp = open_file(file, buf, F_READ, !COMPLAIN, QUIET);
  1005. X    if (fp == NIL)
  1006. X        return NO;    /* joverc returns an integer */
  1007. X
  1008. X    /* Catch any errors, here, and do the right thing with them,
  1009. X       and then restore the error handle to whoever did a setjmp
  1010. X       last. */
  1011. X
  1012. X    InJoverc += 1;
  1013. X    push_env(savejmp);
  1014. X    if (setjmp(mainjmp)) {
  1015. X        Buffer    *savebuf = curbuf;
  1016. X
  1017. X        SetBuf(do_select((Window *) 0, "RC errors"));
  1018. X        ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO);
  1019. X        unmodify();
  1020. X        SetBuf(savebuf);
  1021. X        Asking = 0;
  1022. X    }
  1023. X    if (!eof) do {
  1024. X        eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
  1025. X        lnum += 1;
  1026. X        if (lbuf[0] == '#')        /* a comment */
  1027. X            continue;
  1028. X#ifndef MAC
  1029. X        if (casencmp(lbuf, "if", 2) == 0) {
  1030. X            char    cmd[128];
  1031. X
  1032. X            if (IfStatus != IF_UNBOUND)
  1033. X                complain("[Cannot have nested if's]");
  1034. X            if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
  1035. X                complain("[If syntax error]");
  1036. X            putmatch(1, cmd, sizeof cmd);
  1037. X            IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
  1038. X            continue;
  1039. X        } else if (casencmp(lbuf, "else", 4) == 0) {
  1040. X            if (IfStatus == IF_UNBOUND)
  1041. X                complain("[Unexpected `else']");
  1042. X            IfStatus = !IfStatus;
  1043. X            continue;
  1044. X        } else if (casencmp(lbuf, "endif", 5) == 0) {
  1045. X            if (IfStatus == IF_UNBOUND)
  1046. X                complain("[Unexpected `endif']");
  1047. X            IfStatus = IF_UNBOUND;
  1048. X            continue;
  1049. X        }
  1050. X#endif
  1051. X        if (IfStatus == IF_FALSE)
  1052. X            continue;
  1053. X        (void) strcat(lbuf, "\n");
  1054. X        Inputp = lbuf;
  1055. X        while (*Inputp == ' ' || *Inputp == '\t')
  1056. X            Inputp += 1;    /* skip white space */
  1057. X        Extend();
  1058. X    } while (!eof);
  1059. X
  1060. X    f_close(fp);
  1061. X    pop_env(savejmp);
  1062. X    Inputp = 0;
  1063. X    Asking = 0;
  1064. X    InJoverc -= 1;
  1065. X    if (IfStatus != IF_UNBOUND)
  1066. X        complain("[Missing endif]");
  1067. X    return 1;
  1068. X}
  1069. END_OF_FILE
  1070. if test 19914 -ne `wc -c <'./extend.c'`; then
  1071.     echo shar: \"'./extend.c'\" unpacked with wrong size!
  1072. fi
  1073. # end of './extend.c'
  1074. fi
  1075. if test -f './re.c' -a "${1}" != "-c" ; then 
  1076.   echo shar: Will not clobber existing file \"'./re.c'\"
  1077. else
  1078. echo shar: Extracting \"'./re.c'\" \(18437 characters\)
  1079. sed "s/^X//" >'./re.c' <<'END_OF_FILE'
  1080. X/***************************************************************************
  1081. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  1082. X * is provided to you without charge, and with no warranty.  You may give  *
  1083. X * away copies of JOVE, including sources, provided that this notice is    *
  1084. X * included in all the files.                                              *
  1085. X ***************************************************************************/
  1086. X
  1087. X/* search package */
  1088. X
  1089. X#include "jove.h"
  1090. X#include "ctype.h"
  1091. X#ifdef MAC
  1092. X#    undef private
  1093. X#    define private
  1094. X#endif
  1095. X
  1096. X#ifdef    LINT_ARGS
  1097. private char * insert(char *, char *, int);
  1098. X
  1099. private void
  1100. X    REreset(void),
  1101. X    search(int, int, int);
  1102. private int
  1103. X    backref(int, char *),
  1104. X    do_comp(int),
  1105. X    member(char *, int, int),
  1106. X    REgetc(void),
  1107. X    REmatch(char *, char *);
  1108. X#else
  1109. private char * insert();
  1110. X
  1111. private void
  1112. X    REreset(),
  1113. X    search();
  1114. private int
  1115. X    backref(),
  1116. X    do_comp(),
  1117. X    member(),
  1118. X    REgetc(),
  1119. X    REmatch();
  1120. X#endif    /* LINT_ARGS */
  1121. X
  1122. X#ifdef MAC
  1123. X#    undef private
  1124. X#    define private static
  1125. X#endif
  1126. X
  1127. X#define NALTS    16    /* number of alternate search strings */
  1128. X
  1129. char    searchstr[128],
  1130. X    compbuf[256],        /* global default compbuf */
  1131. X    rep_search[128],    /* replace search string */
  1132. X    rep_str[128],        /* contains replacement string */
  1133. X    *cur_compb,        /* usually points at compbuf */
  1134. X    REbuf[LBSIZE],        /* points at line we're scanning */
  1135. X    *alternates[NALTS];
  1136. X
  1137. int    REdirection;
  1138. X
  1139. int    CaseIgnore = 0,
  1140. X    WrapScan = 0,
  1141. X    UseRE = 0;
  1142. X
  1143. X#define cind_cmp(a, b)    (CaseEquiv[a] == CaseEquiv[b])
  1144. X
  1145. private int    REpeekc;
  1146. private char    *REptr;
  1147. X
  1148. private int
  1149. REgetc()
  1150. X{
  1151. X    int    c;
  1152. X
  1153. X    if ((c = REpeekc) != -1)
  1154. X        REpeekc = -1;
  1155. X    else if (*REptr)
  1156. X        c = *REptr++;
  1157. X    else
  1158. X        c = 0;
  1159. X
  1160. X    return c;
  1161. X}
  1162. X
  1163. X#define STAR     01    /* Match any number of last RE. */
  1164. X#define AT_BOL    2    /* ^ */
  1165. X#define AT_EOL    4    /* $ */
  1166. X#define AT_BOW    6    /* \< */
  1167. X#define AT_EOW    8    /* \> */
  1168. X#define OPENP    10    /* \( */
  1169. X#define CLOSEP    12    /* \) */
  1170. X#define CURLYB    14    /* \{ */
  1171. X
  1172. X#define NOSTR    14    /* Codes <= NOSTR can't be *'d. */
  1173. X
  1174. X#define ANYC    NOSTR+2        /* . */
  1175. X#define NORMC    ANYC+2        /* normal character */
  1176. X#define CINDC    NORMC+2        /* case independent character */
  1177. X#define ONE_OF    CINDC+2        /* [xxx] */
  1178. X#define NONE_OF    ONE_OF+2    /* [^xxx] */
  1179. X#define BACKREF    NONE_OF+2    /* \# */
  1180. X#define EOP    BACKREF+2    /* end of pattern */
  1181. X
  1182. X#define NPAR    10    /* [0-9] - 0th is the entire matched string, i.e. & */
  1183. private int    nparens;
  1184. private char    *comp_p,
  1185. X        *start_p,
  1186. X        **alt_p,
  1187. X        **alt_endp;
  1188. X
  1189. void
  1190. REcompile(pattern, re, into_buf, alt_bufp)
  1191. char    *pattern,
  1192. X    *into_buf,
  1193. X    **alt_bufp;
  1194. X{
  1195. X    REptr = pattern;
  1196. X    REpeekc = -1;
  1197. X    comp_p = cur_compb = start_p = into_buf;
  1198. X    alt_p = alt_bufp;
  1199. X    alt_endp = alt_p + NALTS;
  1200. X    *alt_p++ = comp_p;
  1201. X    nparens = 0;
  1202. X    (void) do_comp(re ? OKAY_RE : NORM);
  1203. X    *alt_p = 0;
  1204. X}
  1205. X
  1206. X/* compile the pattern into an internal code */
  1207. X
  1208. private int
  1209. do_comp(kind)
  1210. X{
  1211. X    char    *last_p,
  1212. X        *chr_cnt = 0;
  1213. X    int    parens[NPAR],
  1214. X        *parenp,
  1215. X        c,
  1216. X        ret_code;
  1217. X
  1218. X    parenp = parens;
  1219. X    last_p = 0;
  1220. X    ret_code = 1;
  1221. X
  1222. X    if (kind == OKAY_RE) {
  1223. X        *comp_p++ = OPENP;
  1224. X        *comp_p++ = nparens;
  1225. X        *parenp++ = nparens++;
  1226. X        start_p = comp_p;
  1227. X    }
  1228. X
  1229. X    while (c = REgetc()) {
  1230. X        if (comp_p > &cur_compb[(sizeof compbuf) - 6])
  1231. toolong:        complain("Search string too long/complex.");
  1232. X        if (c != '*')
  1233. X            last_p = comp_p;
  1234. X
  1235. X        if (kind == NORM && index(".[*", c) != 0)
  1236. X            goto defchar;
  1237. X        switch (c) {
  1238. X        case '\\':
  1239. X            switch (c = REgetc()) {
  1240. X            case 0:
  1241. X                complain("Premature end of pattern.");
  1242. X
  1243. X            case '{':
  1244. X                {
  1245. X                    char    *wcntp;        /* word count */
  1246. X
  1247. X                    *comp_p++ = CURLYB;
  1248. X                    wcntp = comp_p;
  1249. X                    *comp_p++ = 0;
  1250. X                    for (;;) {
  1251. X                        int    comp_val;
  1252. X                        char    *comp_len;
  1253. X
  1254. X                        comp_len = comp_p++;
  1255. X                        comp_val = do_comp(IN_CB);
  1256. X                        *comp_len = comp_p - comp_len;
  1257. X                        (*wcntp) += 1;
  1258. X                        if (comp_val == 0)
  1259. X                            break;
  1260. X                    }
  1261. X                    break;
  1262. X                }
  1263. X
  1264. X            case '}':
  1265. X                if (kind != IN_CB)
  1266. X                    complain("Unexpected \}.");
  1267. X                ret_code = 0;
  1268. X                goto outahere;
  1269. X
  1270. X            case '(':
  1271. X                if (nparens >= NPAR)
  1272. X                    complain("Too many ('s; max is %d.", NPAR);
  1273. X                *comp_p++ = OPENP;
  1274. X                *comp_p++ = nparens;
  1275. X                *parenp++ = nparens++;
  1276. X                break;
  1277. X
  1278. X            case ')':
  1279. X                if (parenp == parens)
  1280. X                    complain("Too many )'s.");
  1281. X                *comp_p++ = CLOSEP;
  1282. X                *comp_p++ = *--parenp;
  1283. X                break;
  1284. X
  1285. X            case '|':
  1286. X                if (alt_p >= alt_endp)
  1287. X                    complain("Too many alternates; max %d.", NALTS);
  1288. X                *comp_p++ = CLOSEP;
  1289. X                *comp_p++ = *--parenp;
  1290. X                *comp_p++ = EOP;
  1291. X                *alt_p++ = comp_p;
  1292. X                nparens = 0;
  1293. X                *comp_p++ = OPENP;
  1294. X                *comp_p++ = nparens;
  1295. X                *parenp++ = nparens++;
  1296. X                start_p = comp_p;
  1297. X                break;
  1298. X
  1299. X            case '1':
  1300. X            case '2':
  1301. X            case '3':
  1302. X            case '4':
  1303. X            case '5':
  1304. X            case '6':
  1305. X            case '7':
  1306. X            case '8':
  1307. X            case '9':
  1308. X                *comp_p++ = BACKREF;
  1309. X                *comp_p++ = c - '0';
  1310. X                break;
  1311. X
  1312. X            case '<':
  1313. X                *comp_p++ = AT_BOW;
  1314. X                break;
  1315. X
  1316. X            case '>':
  1317. X                *comp_p++ = AT_EOW;
  1318. X                break;
  1319. X
  1320. X            default:
  1321. X                goto defchar;
  1322. X            }
  1323. X            break;
  1324. X
  1325. X        case ',':
  1326. X            if (kind != IN_CB)
  1327. X                goto defchar;
  1328. X            goto outahere;
  1329. X
  1330. X        case '.':
  1331. X            *comp_p++ = ANYC;
  1332. X            break;
  1333. X
  1334. X        case '^':
  1335. X            if (comp_p == start_p) {
  1336. X                *comp_p++ = AT_BOL;
  1337. X                break;
  1338. X            }
  1339. X            goto defchar;
  1340. X
  1341. X        case '$':
  1342. X            if ((REpeekc = REgetc()) != 0 && REpeekc != '\\')
  1343. X                goto defchar;
  1344. X            *comp_p++ = AT_EOL;
  1345. X            break;
  1346. X
  1347. X        case '[':
  1348. X            {
  1349. X                int    chrcnt;
  1350. X
  1351. X                *comp_p++ = ONE_OF;
  1352. X            if (comp_p + 16 >= &cur_compb[(sizeof compbuf)])
  1353. X                goto toolong;
  1354. X                bzero(comp_p, 16);
  1355. X                if ((REpeekc = REgetc()) == '^') {
  1356. X                    *last_p = NONE_OF;
  1357. X                    /* Get it for real this time. */
  1358. X                    (void) REgetc();
  1359. X                }
  1360. X                chrcnt = 1;
  1361. X                while ((c = REgetc()) != ']' && c != 0) {
  1362. X                    if (c == '\\')
  1363. X                        c = REgetc();
  1364. X                else if ((REpeekc = REgetc()) == '-') {
  1365. X                    int    c2;
  1366. X
  1367. X                    (void) REgetc();     /* reread '-' */
  1368. X                    c2 = REgetc();
  1369. X                    while (c < c2) {
  1370. X                        comp_p[c/8] |= (1 << (c%8));
  1371. X                        c += 1;
  1372. X                    }
  1373. X                }
  1374. X                comp_p[c/8] |= (1 << (c%8));
  1375. X                    chrcnt += 1;
  1376. X                }
  1377. X                if (c == 0)
  1378. X                    complain("Missing ].");
  1379. X                if (chrcnt == 1)
  1380. X                    complain("Empty [].");
  1381. X                comp_p += 16;
  1382. X                break;
  1383. X            }
  1384. X
  1385. X        case '*':
  1386. X            if (last_p == 0 || *last_p <= NOSTR)
  1387. X                goto defchar;
  1388. X
  1389. X            /* The * operator applies only to the previous
  1390. X               character.  If we were building a chr_cnt at
  1391. X               the time we got the *, we have to remove the
  1392. X               last character from the chr_cnt (by decrementing
  1393. X               *chr_cnt) and replacing it with a new STAR entry.
  1394. X
  1395. X               If we are decrementing the count to 0, we just
  1396. X               delete the chr_cnt entry altogether, replacing
  1397. X               it with the STAR entry. */
  1398. X
  1399. X            if (chr_cnt) {
  1400. X                char    lastc = chr_cnt[*chr_cnt];
  1401. X             /* The * operator applies only to the previous
  1402. X                character.  If we were building a chr_cnt at
  1403. X                the time we got the *, we have to remove the
  1404. X                last character from the chr_cnt (by decrementing
  1405. X                *chr_cnt) and replacing it with a new STAR entry.
  1406. X                If we are decrementing the count to 0, we just
  1407. X                delete the chr_cnt entry altogether, replacing
  1408. X                it with the STAR entry. */
  1409. X                 if (*chr_cnt == 1) {
  1410. X                     comp_p = chr_cnt;
  1411. X                     comp_p[-1] |= STAR;
  1412. X                     *comp_p++ = lastc;
  1413. X                 } else {
  1414. X                     comp_p = chr_cnt + *chr_cnt;
  1415. X                     (*chr_cnt) -= 1;
  1416. X                     *comp_p++ = chr_cnt[-1] | STAR;
  1417. X                     *comp_p++ = lastc;
  1418. X                 }
  1419. X            } else
  1420. X                *last_p |= STAR;
  1421. X            break;
  1422. X        default:
  1423. defchar:        if (chr_cnt)
  1424. X                (*chr_cnt) += 1;
  1425. X            else {
  1426. X                *comp_p++ = (CaseIgnore) ? CINDC : NORMC;
  1427. X                chr_cnt = comp_p++;
  1428. X                *chr_cnt = 1;   /* last_p[1] = 1; */
  1429. X            }
  1430. X            *comp_p++ = c;
  1431. X            continue;
  1432. X        }
  1433. X        chr_cnt = FALSE;
  1434. X    }
  1435. outahere:
  1436. X    /* End of pattern, let's do some error checking. */
  1437. X    if (kind == OKAY_RE) {
  1438. X        *comp_p++ = CLOSEP;
  1439. X        *comp_p++ = *--parenp;
  1440. X    }
  1441. X    if (parenp != parens)
  1442. X        complain("Unmatched ()'s.");
  1443. X    if (kind == IN_CB && c == 0)    /* End of pattern with \}. */
  1444. X        complain("Missing \}.");
  1445. X    *comp_p++ = EOP;
  1446. X
  1447. X    return ret_code;
  1448. X}
  1449. X
  1450. private char    *pstrtlst[NPAR],    /* index into REbuf */
  1451. X        *pendlst[NPAR],
  1452. X        *REbolp,
  1453. X        *locs,
  1454. X        *loc1,
  1455. X        *loc2;
  1456. X
  1457. int    REbom,
  1458. X    REeom,        /* beginning and end of match */
  1459. X    REalt_num;    /* if alternatives, which one matched? */
  1460. X
  1461. private int
  1462. backref(n, linep)
  1463. register char    *linep;
  1464. X{
  1465. X    register char    *backsp,
  1466. X            *backep;
  1467. X
  1468. X    backsp = pstrtlst[n];
  1469. X    backep = pendlst[n];
  1470. X    while (*backsp++ == *linep++)
  1471. X        if (backsp >= backep)
  1472. X            return 1;
  1473. X    return 0;
  1474. X}
  1475. X
  1476. private int
  1477. member(comp_p, c, af)
  1478. register char    *comp_p;
  1479. register int    c,
  1480. X        af;
  1481. X{
  1482. X    if (c == 0)
  1483. X        return 0;    /* try to match EOL always fails */
  1484. X    if (comp_p[c/8] & (1 << (c%8)))
  1485. X        return af;
  1486. X    return !af;
  1487. X}
  1488. X
  1489. private int
  1490. REmatch(linep, comp_p)
  1491. register char    *linep,
  1492. X        *comp_p;
  1493. X{
  1494. X    char    *first_p = linep;
  1495. X    register int    n;
  1496. X
  1497. X    for (;;) switch (*comp_p++) {
  1498. X    case NORMC:
  1499. X        n = *comp_p++;
  1500. X        while (--n >= 0)
  1501. X            if (*linep++ != *comp_p++)
  1502. X                return 0;
  1503. X        continue;
  1504. X
  1505. X    case CINDC:    /* case independent comparison */
  1506. X        n = *comp_p++;
  1507. X        while (--n >= 0)
  1508. X            if (!cind_cmp(*linep++, *comp_p++))
  1509. X                return 0;
  1510. X        continue;
  1511. X
  1512. X    case EOP:
  1513. X        loc2 = linep;
  1514. X        REeom = (loc2 - REbolp);
  1515. X        return 1;    /* Success! */
  1516. X
  1517. X    case AT_BOL:
  1518. X        if (linep == REbolp)
  1519. X            continue;
  1520. X        return 0;
  1521. X
  1522. X    case AT_EOL:
  1523. X        if (*linep == 0)
  1524. X            continue;
  1525. X        return 0;
  1526. X
  1527. X    case ANYC:
  1528. X        if (*linep++ != 0)
  1529. X            continue;
  1530. X        return 0;
  1531. X
  1532. X    case AT_BOW:
  1533. X        if (ismword(*linep) && (linep == REbolp || !ismword(linep[-1])))
  1534. X            continue;
  1535. X        return 0;
  1536. X
  1537. X    case AT_EOW:
  1538. X        if ((*linep == 0 || !ismword(*linep)) &&
  1539. X            (linep != REbolp && ismword(linep[-1])))
  1540. X            continue;
  1541. X        return 0;
  1542. X
  1543. X    case ONE_OF:
  1544. X    case NONE_OF:
  1545. X        if (member(comp_p, *linep++, comp_p[-1] == ONE_OF)) {
  1546. X            comp_p += 16;
  1547. X            continue;
  1548. X        }
  1549. X        return 0;
  1550. X
  1551. X    case OPENP:
  1552. X        pstrtlst[*comp_p++] = linep;
  1553. X        continue;
  1554. X
  1555. X    case CLOSEP:
  1556. X        pendlst[*comp_p++] = linep;
  1557. X        continue;
  1558. X
  1559. X    case BACKREF:
  1560. X        if (pstrtlst[n = *comp_p++] == 0) {
  1561. X            s_mess("\\%d was not specified.", n + 1);
  1562. X            return 0;
  1563. X        }
  1564. X        if (backref(n, linep)) {
  1565. X            linep += pendlst[n] - pstrtlst[n];
  1566. X            continue;
  1567. X        }
  1568. X        return 0;
  1569. X
  1570. X    case CURLYB:
  1571. X        {
  1572. X            int    wcnt,
  1573. X                any;
  1574. X
  1575. X            wcnt = *comp_p++;
  1576. X            any = 0;
  1577. X
  1578. X            while (--wcnt >= 0) {
  1579. X                if (any == 0)
  1580. X                    any = REmatch(linep, comp_p + 1);
  1581. X                comp_p += *comp_p;
  1582. X            }
  1583. X            if (any == 0)
  1584. X                return 0;
  1585. X            linep = loc2;
  1586. X            continue;
  1587. X        }
  1588. X
  1589. X    case ANYC | STAR:
  1590. X        first_p = linep;
  1591. X        while (*linep++)
  1592. X            ;
  1593. X        goto star;
  1594. X
  1595. X    case NORMC | STAR:
  1596. X        first_p = linep;
  1597. X        while (*comp_p == *linep++)
  1598. X            ;
  1599. X        comp_p += 1;
  1600. X        goto star;
  1601. X
  1602. X    case CINDC | STAR:
  1603. X        first_p = linep;
  1604. X        while (cind_cmp(*comp_p, *linep++))
  1605. X            ;
  1606. X        comp_p += 1;
  1607. X        goto star;
  1608. X
  1609. X    case ONE_OF | STAR:
  1610. X    case NONE_OF | STAR:
  1611. X        first_p = linep;
  1612. X        while (member(comp_p, *linep++, comp_p[-1] == (ONE_OF | STAR)))
  1613. X            ;
  1614. X        comp_p += 16;
  1615. X        goto star;
  1616. X
  1617. X    case BACKREF | STAR:
  1618. X        first_p = linep;
  1619. X        n = *comp_p++;
  1620. X        while (backref(n, linep))
  1621. X            linep += pendlst[n] - pstrtlst[n];
  1622. X        while (linep >= first_p) {
  1623. X            if (REmatch(linep, comp_p))
  1624. X                return 1;
  1625. X            linep -= pendlst[n] - pstrtlst[n];
  1626. X        }
  1627. X        continue;
  1628. X
  1629. star:        do {
  1630. X            linep -= 1;
  1631. X            if (linep < locs)
  1632. X                break;
  1633. X            if (REmatch(linep, comp_p))
  1634. X                return 1;
  1635. X        } while (linep > first_p);
  1636. X        return 0;
  1637. X
  1638. X    default:
  1639. X        complain("RE error match (%d).", comp_p[-1]);
  1640. X    }
  1641. X    /* NOTREACHED. */
  1642. X}
  1643. X
  1644. private void
  1645. REreset()
  1646. X{
  1647. X    register int    i;
  1648. X
  1649. X    for (i = 0; i < NPAR; i++)
  1650. X        pstrtlst[i] = pendlst[i] = 0;
  1651. X}
  1652. X
  1653. X/* Index LINE at OFFSET, the compiled EXPR, with alternates ALTS.  If
  1654. X   lbuf_okay is nonzero it's okay to use linebuf if LINE is the current
  1655. X   line.  This should save lots of time in things like paren matching in
  1656. X   LISP mode.  Saves all that copying from linebuf to REbuf.  substitute()
  1657. X   is the guy who calls re_lindex with lbuf_okay as 0, since the substitution
  1658. X   gets placed in linebuf ... doesn't work too well when the source and
  1659. X   destination strings are the same.  I hate all these arguments!
  1660. X
  1661. X   This code is cumbersome, repetetive for reasons of efficiency.  Fast
  1662. X   search is a must as far as I am concerned. */
  1663. X
  1664. int
  1665. re_lindex(line, offset, expr, alts, lbuf_okay)
  1666. Line    *line;
  1667. char    *expr,
  1668. X    **alts;
  1669. X{
  1670. X    int    isquick;
  1671. X    register int    firstc,
  1672. X            c;
  1673. X    register char    *resp;
  1674. X
  1675. X    REreset();
  1676. X    if (lbuf_okay) {
  1677. X        REbolp = lbptr(line);
  1678. X        if (offset == -1)
  1679. X            offset = strlen(REbolp);    /* arg! */
  1680. X    } else {
  1681. X        REbolp = ltobuf(line, REbuf);
  1682. X        if (offset == -1) {    /* Reverse search, find end of line. */
  1683. X            extern int    Jr_Len;
  1684. X
  1685. X            offset = Jr_Len;    /* Just Read Len. */
  1686. X        }
  1687. X    }
  1688. X    resp = REbolp;
  1689. X    isquick = ((expr[0] == NORMC || expr[0] == CINDC) &&
  1690. X           (alternates[1] == 0));
  1691. X    if (isquick) {
  1692. X        firstc = expr[2];
  1693. X        if (expr[0] == CINDC)
  1694. X            firstc = CaseEquiv[firstc];
  1695. X    }
  1696. X    locs = REbolp + offset;
  1697. X
  1698. X    if (REdirection == FORWARD) {
  1699. X        do {
  1700. X        char    **altp = alts;
  1701. X
  1702. X        if (isquick) {
  1703. X            if (expr[0] == NORMC)
  1704. X                while ((c = *locs++) != 0 && c != firstc)
  1705. X                    ;
  1706. X            else
  1707. X                while (((c = *locs++) != 0) &&
  1708. X                    (CaseEquiv[c] != firstc))
  1709. X                    ;
  1710. X            if (*--locs == 0)
  1711. X                break;
  1712. X        }
  1713. X        REalt_num = 1;
  1714. X        while (*altp) {
  1715. X            if (REmatch(locs, *altp++)) {
  1716. X                loc1 = locs;
  1717. X                REbom = loc1 - REbolp;
  1718. X                return 1;
  1719. X            }
  1720. X            REalt_num += 1;
  1721. X        }
  1722. X        } while (*locs++);
  1723. X    } else {
  1724. X        do {
  1725. X        char    **altp = alts;
  1726. X
  1727. X        if (isquick) {
  1728. X            if (expr[0] == NORMC) {
  1729. X                while (locs >= REbolp && *locs-- != firstc)
  1730. X                    ;
  1731. X                if (*++locs != firstc)
  1732. X                    break;
  1733. X            } else {
  1734. X                while (locs >= REbolp && CaseEquiv[*locs--] != firstc)
  1735. X                    ;
  1736. X                if (CaseEquiv[*++locs] != firstc)
  1737. X                    break;
  1738. X            }
  1739. X        }
  1740. X        REalt_num = 1;
  1741. X        while (*altp) {
  1742. X            if (REmatch(locs, *altp++)) {
  1743. X                loc1 = locs;
  1744. X                REbom = loc1 - REbolp;
  1745. X                return 1;
  1746. X            }
  1747. X            REalt_num += 1;
  1748. X        }
  1749. X        } while (--locs >= resp);
  1750. X    }
  1751. X
  1752. X    return 0;
  1753. X}
  1754. X
  1755. int    okay_wrap = 0;    /* Do a wrap search ... not when we're
  1756. X               parsing errors ... */
  1757. X
  1758. Bufpos *
  1759. dosearch(pattern, dir, re)
  1760. char    *pattern;
  1761. X{
  1762. X    Bufpos    *pos;
  1763. X
  1764. X    if (bobp() && eobp())    /* Can't match!  There's no buffer. */
  1765. X        return 0;
  1766. X
  1767. X    REcompile(pattern, re, compbuf, alternates);
  1768. X
  1769. X    pos = docompiled(dir, compbuf, alternates);
  1770. X    return pos;
  1771. X}
  1772. X
  1773. Bufpos *
  1774. docompiled(dir, expr, alts)
  1775. char    *expr,
  1776. X    **alts;
  1777. X{
  1778. X    static Bufpos    ret;
  1779. X    register Line    *lp;
  1780. X    register int    offset;
  1781. X    int    we_wrapped = NO;
  1782. X
  1783. X    lsave();
  1784. X    /* Search now lsave()'s so it doesn't make any assumptions on
  1785. X       whether the the contents of curline/curchar are in linebuf.
  1786. X       Nowhere does search write all over linebuf.  However, we have to
  1787. X       be careful about what calls we make here, because many of them
  1788. X       assume (and rightly so) that curline is in linebuf. */
  1789. X
  1790. X    REdirection = dir;
  1791. X    lp = curline;
  1792. X    offset = curchar;
  1793. X    if (dir == BACKWARD) {
  1794. X        if (bobp()) {
  1795. X            if (okay_wrap && WrapScan)
  1796. X                goto doit;
  1797. X            return 0;
  1798. X        }
  1799. X        /* here we simulate BackChar() */
  1800. X        if (bolp()) {
  1801. X            lp = lp->l_prev;
  1802. X            offset = strlen(lbptr(lp));
  1803. X        } else
  1804. X            offset -= 1;
  1805. X    } else if ((dir == FORWARD) &&
  1806. X           (lbptr(lp)[offset] == '\0') &&
  1807. X           !lastp(lp)) {
  1808. X        lp = lp->l_next;
  1809. X        offset = 0;
  1810. X    }
  1811. X
  1812. X    do {
  1813. X        if (re_lindex(lp, offset, expr, alts, YES))
  1814. X            break;
  1815. doit:        lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
  1816. X        if (lp == 0) {
  1817. X            if (okay_wrap && WrapScan) {
  1818. X                lp = (dir == FORWARD) ?
  1819. X                     curbuf->b_first : curbuf->b_last;
  1820. X                we_wrapped = YES;
  1821. X            } else
  1822. X                 break;
  1823. X        }
  1824. X        if (dir == FORWARD)
  1825. X            offset = 0;
  1826. X        else
  1827. X            offset = -1;    /* signals re_lindex ... */
  1828. X    } while (lp != curline);
  1829. X
  1830. X    if (lp == curline && we_wrapped)
  1831. X        lp = 0;
  1832. X    if (lp == 0)
  1833. X        return 0;
  1834. X    ret.p_line = lp;
  1835. X    ret.p_char = (dir == FORWARD) ? REeom : REbom;
  1836. X    return &ret;
  1837. X}
  1838. X
  1839. private char *
  1840. insert(off, endp, which)
  1841. char    *off,
  1842. X    *endp;
  1843. X{
  1844. X    register char    *pp;
  1845. X    register int    n;
  1846. X
  1847. X    n = pendlst[which] - pstrtlst[which];
  1848. X    pp = pstrtlst[which];
  1849. X    while (--n >= 0) {
  1850. X        *off++ = *pp++;
  1851. X        if (off >= endp)
  1852. X            len_error(ERROR);
  1853. X    }
  1854. X    return off;
  1855. X}
  1856. X
  1857. X/* Perform the substitution.  If DELP is nonzero the matched string is
  1858. X   deleted, i.e., the substitution string is not inserted. */
  1859. X
  1860. void
  1861. re_dosub(tobuf, delp)
  1862. char    *tobuf;
  1863. X{
  1864. X    register char    *tp,
  1865. X            *rp,
  1866. X            *repp;
  1867. X    int    c;
  1868. X    char    *endp;
  1869. X
  1870. X    tp = tobuf;
  1871. X    endp = tp + LBSIZE;
  1872. X    rp = REbuf;
  1873. X    repp = rep_str;
  1874. X
  1875. X    while (rp < loc1)
  1876. X        *tp++ = *rp++;
  1877. X
  1878. X    if (!delp) while (c = *repp++) {
  1879. X        if (c == '\\') {
  1880. X            c = *repp++;
  1881. X            if (c == '\0') {
  1882. X                *tp++ = '\\';
  1883. X                  goto endchk;
  1884. X            } else if (c >= '1' && c <= nparens + '1') {
  1885. X                tp = insert(tp, endp, c - '0');
  1886. X                continue;
  1887. X            }
  1888. X        } else if (c == '&') {
  1889. X            tp = insert(tp, endp, 0);
  1890. X            continue;
  1891. X        }
  1892. X        *tp++ = c;
  1893. endchk:        if (tp >= endp)
  1894. X            len_error(ERROR);
  1895. X    }
  1896. X    rp = loc2;
  1897. X    loc2 = REbuf + max(1, tp - tobuf);
  1898. X    REeom = loc2 - REbuf;
  1899. X    /* At least one character past the match, to prevent an infinite
  1900. X       number of replacements in the same position, e.g.,
  1901. X       replace "^" with "". */
  1902. X    while (*tp++ = *rp++)
  1903. X        if (tp >= endp)
  1904. X            len_error(ERROR);
  1905. X}
  1906. X
  1907. void
  1908. putmatch(which, buf, size)
  1909. char    *buf;
  1910. X{
  1911. X    *(insert(buf, buf + size, which)) = 0;
  1912. X}
  1913. X
  1914. void
  1915. setsearch(str)
  1916. char    *str;
  1917. X{
  1918. X    strcpy(searchstr, str);
  1919. X}
  1920. X
  1921. char *
  1922. getsearch()
  1923. X{
  1924. X    return searchstr;
  1925. X}
  1926. X
  1927. void
  1928. RErecur()
  1929. X{
  1930. X    char    sbuf[sizeof searchstr],
  1931. X        cbuf[sizeof compbuf],
  1932. X        repbuf[sizeof rep_str],
  1933. X        *altbuf[NALTS];
  1934. X    int    npars;
  1935. X    Mark    *m = MakeMark(curline, REbom, M_FLOATER);
  1936. X
  1937. X    message("Type C-X C-C to continue with query replace.");
  1938. X
  1939. X    npars = nparens;
  1940. X    byte_copy(compbuf, cbuf, sizeof compbuf);
  1941. X    byte_copy(searchstr, sbuf, sizeof searchstr);
  1942. X    byte_copy(rep_str, repbuf, sizeof rep_str);
  1943. X    byte_copy((char *) alternates, (char *) altbuf, sizeof alternates);
  1944. X    Recur();
  1945. X    nparens = npars;
  1946. X    byte_copy(cbuf, compbuf, sizeof compbuf);
  1947. X    byte_copy(sbuf, searchstr, sizeof searchstr);
  1948. X    byte_copy(repbuf, rep_str, sizeof rep_str);
  1949. X    byte_copy((char *) altbuf, (char *) alternates, sizeof alternates);
  1950. X    if (!is_an_arg())
  1951. X        ToMark(m);
  1952. X    DelMark(m);
  1953. X}
  1954. X
  1955. void
  1956. ForSearch()
  1957. X{
  1958. X    search(FORWARD, UseRE, YES);
  1959. X}
  1960. X
  1961. void
  1962. RevSearch()
  1963. X{
  1964. X    search(BACKWARD, UseRE, YES);
  1965. X}
  1966. X
  1967. void
  1968. FSrchND()
  1969. X{
  1970. X    search(FORWARD, UseRE, NO);
  1971. X}
  1972. X
  1973. void
  1974. RSrchND()
  1975. X{
  1976. X    search(BACKWARD, UseRE, NO);
  1977. X}
  1978. X
  1979. private void
  1980. search(dir, re, setdefault)
  1981. X{
  1982. X    Bufpos    *newdot;
  1983. X    char    *s;
  1984. X
  1985. X    s = ask(searchstr, ProcFmt);
  1986. X    if (setdefault)
  1987. X        setsearch(s);
  1988. X    okay_wrap = YES;
  1989. X    newdot = dosearch(s, dir, re);
  1990. X    okay_wrap = NO;
  1991. X    if (newdot == 0) {
  1992. X        if (WrapScan)
  1993. X            complain("No \"%s\" in buffer.", s);
  1994. X        else
  1995. X            complain("No \"%s\" found to %s.", s,
  1996. X                 (dir == FORWARD) ? "bottom" : "top");
  1997. X    }
  1998. X    PushPntp(newdot->p_line);
  1999. X    SetDot(newdot);
  2000. X}
  2001. X
  2002. X/* Do we match PATTERN at OFFSET in BUF? */
  2003. X
  2004. int
  2005. LookingAt(pattern, buf, offset)
  2006. char    *pattern,
  2007. X    *buf;
  2008. X{
  2009. X    register char    **alt = alternates;
  2010. X
  2011. X    REcompile(pattern, 1, compbuf, alternates);
  2012. X    REreset();
  2013. X    locs = buf + offset;
  2014. X    REbolp = buf;
  2015. X
  2016. X    while (*alt)
  2017. X        if (REmatch(locs, *alt++))
  2018. X            return 1;
  2019. X    return 0;
  2020. X}
  2021. X
  2022. int
  2023. look_at(expr)
  2024. char    *expr;
  2025. X{
  2026. X    REcompile(expr, 0, compbuf, alternates);
  2027. X    REreset();
  2028. X    locs = linebuf + curchar;
  2029. X    REbolp = linebuf;
  2030. X    if (REmatch(locs, alternates[0]))
  2031. X        return 1;
  2032. X    return 0;
  2033. X}
  2034. X
  2035. END_OF_FILE
  2036. if test 18437 -ne `wc -c <'./re.c'`; then
  2037.     echo shar: \"'./re.c'\" unpacked with wrong size!
  2038. fi
  2039. # end of './re.c'
  2040. fi
  2041. echo shar: End of archive 10 \(of 21\).
  2042. cp /dev/null ark10isdone
  2043. MISSING=""
  2044. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  2045.     if test ! -f ark${I}isdone ; then
  2046.     MISSING="${MISSING} ${I}"
  2047.     fi
  2048. done
  2049. if test "${MISSING}" = "" ; then
  2050.     echo You have unpacked all 21 archives.
  2051.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2052. else
  2053.     echo You still need to unpack the following archives:
  2054.     echo "        " ${MISSING}
  2055. fi
  2056. ##  End of shell archive.
  2057. exit 0
  2058.